package com.nulldev.util.web.nTube.pages.proxying;

import java.io.InputStream;
import java.time.Duration;

import com.nulldev.util.VariableAPI.StringsUtil;
import com.nulldev.util.concurrency.threadIt.v4.asyncTasks.AsyncTaskCallback;
import com.nulldev.util.concurrency.threadIt.v4.emapi.cntft.ControllableFutureTask;
import com.nulldev.util.logging.Logger;
import com.nulldev.util.logging.LoggerFactory;
import com.nulldev.util.web.HttpClient.HttpClient;
import com.nulldev.util.web.HttpClient.HttpMethod;
import com.nulldev.util.web.HttpClient.HttpResponse;
import com.nulldev.util.web.HttpServer3.Response;
import com.nulldev.util.web.HttpServer3.pages.v3.ASyncHttpPage3;
import com.nulldev.util.web.URLUtils.URLUtils;
import com.nulldev.util.web.YouTubeExtractor.YouTubeExtractor;

public class YTChatProxy extends ASyncHttpPage3 {

	public YTChatProxy() {
		super("/youtubei/v1/live_chat/get_live_chat");
		super.setCachingMethod(CachingMethod.NO_CACHE);
		super.setCaptchaExclusion(true);
	}

	protected static final String[] DRM_EXCLUEDED_HEADERS = new String[]
		{ "X-Goog-Visitor-Id", "X-YouTube-Ad-Signals", "X-YouTube-Time-Zone", "X-YouTube-Utc-Offset", "Origin", "Referer", "Host", "Accept-Encoding",
				"User-Agent", "Connection" };
	private final static Logger log = LoggerFactory.getLogger();

	@Override
	public void onFutureRequest(final Request request, final ControllableFutureTask<Response> r) {
		try {
			/*
			 * YouTube for some reason lies to us and claims compression even if it sends a
			 * raw, un-compressed stream.
			 * 
			 * (bonus: this breaks keep-alive)
			 */
			final boolean WORKAROUND_FORCE_DISABLE_COMPRESSION = request.url().startsWith("/youtubei/v1/live_chat/get_live_chat");
			final String url = "https://www.youtube.com" + request.url();
			final Object stream = request.hasInputStream() ? request.getInputStream() : null;
			HttpClient.getStream().url(url).header("User-Agent", request.header("User-Agent", URLUtils.STANDARD_USERAGENT)).timeout(Duration.ofSeconds(30))
					.headers(YouTubeExtractor.DEFAULT_COOKIES).headers(request.headersAsEntries(DRM_EXCLUEDED_HEADERS))
					.createTaskAndRun(HttpMethod.convert(request.getType()), stream).addCallback(new AsyncTaskCallback<HttpResponse<InputStream>>() {

						@SuppressWarnings("resource")
						@Override
						public void onCompletion(final HttpResponse<InputStream> o) {
							final long length = o.length();
							final boolean hasEncoding = WORKAROUND_FORCE_DISABLE_COMPRESSION ? false
									: o.headers().containsKey("content-encoding") || o.headers().containsKey("Content-Encoding");
							String ce = null;
							try {
								if (hasEncoding) {
									if (o.headers().containsKey("Content-Encoding")) {
										ce = o.headers().get("Content-Encoding").get(0);
									} else {
										ce = o.headers().get("content-encoding").get(0);
									}
								}
							} catch (Exception e) {
								log.error(e);
							}
							if (ce != null && hasEncoding && WORKAROUND_FORCE_DISABLE_COMPRESSION)
								log.warn("[chat-proxy] Attempting to proxy with compression present: ce=" + ce);
							r.complete(new Response(o.status(), o.data()).deferCompression((!hasEncoding || ce != null)).setNativeEncoding(hasEncoding, ce)
									.requestKeepAliveDisable(WORKAROUND_FORCE_DISABLE_COMPRESSION)
									.header("Content-Length", length <= -1 ? null : String.valueOf(length))
									.header("Content-Type", StringsUtil.join(o.headers().get("Content-Type"), ";")));
						}

						@Override
						public void onError(Throwable e) {
							r.fail(e);
						}
					}).waitTillCompletion();
		} catch (Throwable ex) {
			r.fail(ex);
		}
	}

}
